package com.wiloon.java.network.network.netty.tls;

//http://www.infoq.com/cn/articles/netty-security

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.LengthFieldPrepender;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.handler.ssl.SslHandler;
import io.netty.util.CharsetUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
import java.io.FileInputStream;
import java.security.KeyStore;

public class TlsServer {
    private static Logger logger = LoggerFactory.getLogger(TlsServer.class);
    private static final String IP = "127.0.0.1";
    private static final int PORT = 9000;


    public static void main(String[] args) {
        TlsServer tlsServer = new TlsServer();
        tlsServer.run();
    }


    public void run() {
        ServerBootstrap bootstrap = new ServerBootstrap();
        EventLoopGroup parentGroup = new NioEventLoopGroup(2);
        EventLoopGroup childGroup = new NioEventLoopGroup(4);

        bootstrap.group(parentGroup, childGroup);
        bootstrap.channel(NioServerSocketChannel.class);
        bootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
            @Override
            protected void initChannel(SocketChannel ch) throws Exception {
                ChannelPipeline pipeline = ch.pipeline();
                pipeline.addLast("frameDecoder", new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 4, 0, 4));
                pipeline.addLast("frameEncoder", new LengthFieldPrepender(4));
                pipeline.addLast("decoder", new StringDecoder(CharsetUtil.UTF_8));
                pipeline.addLast("encoder", new StringEncoder(CharsetUtil.UTF_8));
                pipeline.addLast(new ServerHandler());

                KeyManagerFactory kmf = null;
                KeyStore keyStore = KeyStore.getInstance("JKS");
                keyStore.load(new FileInputStream("/home/roy/workspace/tmp/sChat.jks"), "sNetty".toCharArray());
                kmf = KeyManagerFactory.getInstance("Sunx509");
                kmf.init(keyStore, "sNetty".toCharArray());
                SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
                logger.info("ssl protocol:{}", sslContext.getProtocol());
                sslContext.init(kmf.getKeyManagers(), null, null);
                SSLEngine engine = sslContext.createSSLEngine();
                engine.setUseClientMode(false);
                engine.setNeedClientAuth(false);
                pipeline.addFirst("ssl", new SslHandler(engine));
            }
        });

        try {
            bootstrap.bind(IP, PORT).sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        logger.info("tcp server started,listening: {}:{}", IP, PORT);

    }


    class ServerHandler extends SimpleChannelInboundHandler<Object> {

        private Logger logger = LoggerFactory.getLogger(ServerHandler.class);

        @Override
        public void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
            logger.info("msg from client:{}", msg);
            ctx.channel().writeAndFlush("yes, server is accepted you ,nice !" + msg);
        }

        @Override
        public void exceptionCaught(ChannelHandlerContext ctx,
                                    Throwable cause) throws Exception {
            logger.warn("Unexpected exception from downstream.", cause);
            ctx.close();
        }

        @Override
        public void channelActive(ChannelHandlerContext ctx) throws Exception {
            logger.info("tcp server handler channel active");
            ctx.writeAndFlush("server channel active");
        }
    }


}
